﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Linq;
using System.Collections;
using alib.Debugging;
using alib;
using alib.Enumerable;
using alib.String;
using alib.Collections;
using System.Runtime.CompilerServices;

using agree.schema;

namespace agree
{
	/// (Mark values select a set of outgoing arcs by hashing against feature values,
	/// but carry no information about the type of the originating node. Thus, 
	/// standing alone, they only refer to onwards substructure. The parent type--
	/// giving in turn the appropriate features to hash with--must be carried by 
	/// the caller).
	/// 
	/// In fact, the fact that mark-style APIs do not carry the type of the 
	/// governing node was/is the motivation for creating the ix1-style (aka 
	/// slot-style) operations. Unlike the mark-style just described, slot-style 
	/// APIs support vacuous (i.e. empty path) navigation because any input ix1 identifies 
	/// a unique position in the TFS that can returned as output. Ix1-style can also
	/// refer to the TFS root node itself (impossible with mark-style) via the special
	/// convention Ix1==0.
	///
	/// Note that a TfsSlot (struct) is simply a reference to a TFS, plus an ix1 integer.
	/// The struct implements ITfsSlot, but as always, any struct to an interface should
	/// be carefully considered or avoided.
	/// ITfsSlot is an interface which requires an implementor to provide the same two things.
	/// TfsSlotRef is a class that can be used for C# objects that have an
	/// obvious “TfsSlot-ish” connotation, or as a standalone backing object for ITfsSlot.
	/// IdentitySlotRef is a TfsSlotRef that also implements IIdentity.
	/// 
	/// As an aside, an earlier attempt to resolve the limitations of mark-style
	/// navigation was the ConstraintRef struct, which contains three fields: a
	/// host (governing) node (i.e. an 'Edge': type + out-mark), plus a 
	/// "selected" feature id. This solves the mark ambiguity problem in a manner
	/// that is much less efficient (appropriate-feature lookup and mark hashing is
	/// repeatedly used for every access) but has the advantage of not being 
	/// dependent on details of the ArrayTfs row-style storage scheme.


	public interface ITfsSlot : IIdentity
	{
		Tfs Tfs { get; }
		int SlotIndex { get; }
	};

	public unsafe static class _ts_ext
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		static void get_slot_data(Tfs tfs, int ix1, arr_tfs_entry* pate)
		{
			if (ix1 < 0)
				throw new Exception();
			if (ix1 == 0)
			{
				pate->FeatMark = agree.FeatMark.RootNode;
				pate->e = tfs._top_edge;
			}
			else
				tfs.GetIndexData(ix1, pate);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		static void get_slot_data(ITfsSlot ts, arr_tfs_entry* pate)
		{
			//#if DEBUG
			//			if (ts is TfsSlot)
			//				throw new Exception();
			//#endif
			get_slot_data(ts.Tfs, ts.SlotIndex, pate);
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Edge Edge(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ate.e;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static FeatMark FeatMark(this ITfsSlot ts)
		{
			if (ts.SlotIndex == 0)
				return agree.FeatMark.Invalid;

			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
#if DEBUG
			if (ate.i_feat < 0 || ate.i_feat >= ts.Tfs.ftm.Count)
				return agree.FeatMark.Invalid;
#endif
			return ate.FeatMark;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Edge.Flag FlagsId(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ate.e_FlagsId;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int in_feat(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ate.i_feat;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static FeatureInfo FeatureInfo(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ts.Tfs.ftm[ate.i_feat];
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static String FEATURE(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ts.Tfs.ftm[ate.i_feat].FEATURE;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int in_mark(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ate.mark;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int out_mark(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ate.e_Mark;
		}
		public static TfsSlot Next(this ITfsSlot _ts, int i_feat)
		{
			TfsSlot ts;
			return (ts = new TfsSlot(_ts)).IsValid ? ts[i_feat] : TfsSlot.NotValid;
		}
		public static TfsSlot Next(this ITfsSlot _ts, String s_path)
		{
			TfsSlot ts;
			return (ts = new TfsSlot(_ts)).IsValid ? ts[s_path] : TfsSlot.NotValid;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Type Type(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ts.Tfs.tu.GetEdgeType(ate.e_FlagsId);
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static String TypeNameOrStringValue(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ts.Tfs.tu.TypeNameOrStringValue(ate.e_FlagsId);
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static String TypeNameOrStringValueDisplay(this ITfsSlot ts)
		{
			arr_tfs_entry ate;
			get_slot_data(ts, &ate);
			return ts.Tfs.tu.TypeNameOrStringValueDisplay(ate.e_FlagsId);
		}
		public static String ShortDisplayInfo(this ITfsSlot ts)
		{
			if (ts.Tfs == null)
				return "(null tfs)";
			if (ts.SlotIndex < 0)
				return "(ix1 < 0)";
			return String.Format("{0}{1} {2}",
				ts.GetType().Name,	// note: because of this, do not redirect to TfsSlot
				ts.SlotIndex == 0 ? "" : "[" + ts.SlotIndex.ToString() + "]",
				ts.TypeNameOrStringValue());
		}

		public static TfsSlot[] ListSlots(this ITfsSlot ts)
		{
			return new TfsSlot(ts).ListSlots;
		}
		public static IEnumerable<TfsSlot> DiffListListSlots(this ITfsSlot ts)
		{
			return new TfsSlot(ts).DiffListListSlots;
		}


		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsValid(this ITfsSlot ts)
		{
			return ts.Tfs != null && ts.SlotIndex >= 0;
		}
		public static IEnumerable<FeatMark> AllFeatMarks(this Tfs tfs, Edge e)
		{
			return e.Mark != 0 ?
				tfs.ftm.rgrgfix_by_type[(int)(e.FlagsId & agree.Edge.Flag.MultiIdMask)].Select(fix => new FeatMark(fix, e.Mark)) :
				Enumerable.Empty<FeatMark>();
		}

		public static IEnumerable<int> RootFeatures(this Tfs tfs)
		{
			Debug.Assert(tfs._top_edge.Mark != 0);
			return tfs.ftm.rgrgfix_by_type[(int)(tfs._top_edge.FlagsId & agree.Edge.Flag.MultiIdMask)];
		}

		public static SlotRefArray SlotsBelow(this Tfs tfs, int ix1, bool f_constrained_only = false, Restrictor r = null)
		{
			return new SlotRefArray(tfs, ix1, false, r);
		}
		public static SlotRefArray SlotsBelow(this ITfsSlot ts, bool f_constrained_only = false, Restrictor r = null)
		{
			return new SlotRefArray(ts.Tfs, ts.SlotIndex, f_constrained_only, r);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool Equals(this ITfsSlot _this, ITfsSlot other)
		{
			if (_this == other)
				return true;
			if (_this == default(Object) || other == default(Object))
				return false;
			return _this.Tfs == other.Tfs && _this.SlotIndex == other.SlotIndex;
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{tfs.ToString(),nq}")]
	public class SlotRefArray : IIdentList<TfsSlot>, _ICollection<TfsSlot>, IList
	{
		SlotRefArray(int c, Tfs tfs)
		{
			this.tfs = tfs;
			this.arr = c == 0 ? Collection<TfsSlot>.None : new TfsSlot[c];
		}
		SlotRefArray(Tfs tfs, int[] arr)
			: this(arr == null ? 0 : arr.Length, tfs)
		{
		}
		public SlotRefArray(Tfs _tfs, IEnumerable<int> rgix1)
			: this(rgix1._Count(), _tfs)
		{
			var e = rgix1.GetEnumerator();
			if (e.MoveNext())
			{
				int ix_prev, i = 1;
				arr[0] = new TfsSlot(tfs, ix_prev = e.Current);

				while (e.MoveNext())
					if (ix_prev >= (arr[i++] = new TfsSlot(tfs, ix_prev = e.Current)).ix1)
						throw new Exception();
			}
		}
		public SlotRefArray(Tfs tfs, int ix1, bool f_constrained_only = false, Restrictor r = null)
		{
			this.tfs = tfs;
			if (ix1 < 0)
				this.arr = Collection<TfsSlot>.None;
			else
				this.arr = GetConstraints(tfs, ix1, f_constrained_only, r);
		}
		public unsafe static TfsSlot[] GetConstraints(Tfs tfs, int ix1, bool f_constrained_only = false, Restrictor r = null)
		{
			Edge e;
			FeatMgr ftm;
			if ((ftm = tfs.ftm) == null || ((e = ix1 == 0 ? tfs._top_edge : tfs.entries[ix1 - 1].e).FlagsId & Edge.Flag.EtmNonBareType) == 0)
				return Collection<TfsSlot>.None;

			ushort** rgpfix = r == null ? ftm.r_none.R : r.R;
			ushort* pfix = *(ushort**)((long)rgpfix + ((int)e.FlagsId << 3));
			int ix, j = 0;
			var arr = new TfsSlot[*(pfix - 1)];
			do
				if ((ix = tfs.GetEdgeIndex(*pfix, e.Mark, null)) > 0)
					arr[j++] = new TfsSlot(tfs, ix);
			while (*++pfix != 0xFFFF);
			if (j < arr.Length)
				arr = alib.Array.arr.Resize(arr, j);
			return arr;
		}
		public static TfsSlot[] GetConstraints(ITfsSlot ts, bool f_constrained_only = false, Restrictor r = null)
		{
			return GetConstraints(ts.Tfs, ts.SlotIndex, f_constrained_only, r);
		}

		public static SlotRefArray GetEmptyArr(Tfs tfs) { return new SlotRefArray(tfs, 0); }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly Tfs tfs;

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public SlotRefArray[] _next
		{
			get
			{
				var _ret = new SlotRefArray[this.arr.Length];
				for (int i = 0; i < _ret.Length; i++)
					_ret[i] = new SlotRefArray(tfs, arr[i].ix1);
				return _ret;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly TfsSlot[] arr;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs Tfs { [DebuggerStepThrough] get { return tfs; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TfsSlot this[int i] { [DebuggerStepThrough] get { return arr[i]; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		Object IList.this[int i]
		{
			[DebuggerStepThrough]
			get { return arr[i]; }
			set { throw not.valid; }
		}

		public int Count { [DebuggerStepThrough] get { return arr.Length; } }

		int find_ix1(int ix1)
		{
			int d, i, lo = 0, hi = arr.Length - 1;

			while ((i = hi - lo) >= 0)
				if ((d = arr[i = lo + (i >> 0x1)].ix1 - ix1) == 0)
					return i;
				else if (d < 0)
					lo = i + 1;
				else
					hi = i - 1;

			return -1;
		}

		public int IndexOf(TfsSlot ts) { return find_ix1(ts.ix1); }

		int IList.IndexOf(Object value)
		{
			var ts = value as ITfsSlot;
			return ts == null ? -1 : find_ix1(ts.SlotIndex);
		}

		public bool Contains(TfsSlot ts) { return IndexOf(ts) != -1; }

		bool IList.Contains(Object value)
		{
			var ts = value as ITfsSlot;
			return ts != null && find_ix1(ts.SlotIndex) != -1;
		}

		public IEnumerator<TfsSlot> GetEnumerator() { return arr.Enumerator(); }

		IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

		public void CopyTo(TfsSlot[] array, int index) { this.arr.CopyTo(array, index); }
		void ICollection.CopyTo(Array array, int index) { Array.Copy(this.arr, array, this.arr.Length); }

		public void Add(TfsSlot item) { throw not.valid; }
		public bool Remove(TfsSlot item) { throw not.valid; }
		public void Clear() { throw not.valid; }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public bool IsReadOnly { get { return true; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		Object ICollection.SyncRoot { get { return this; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		bool ICollection.IsSynchronized { get { return false; } }

		int IList.Add(Object value) { throw not.valid; }
		void IList.Insert(int index, Object value) { throw not.valid; }
		void IList.Remove(Object value) { throw not.valid; }
		void IList.RemoveAt(int index) { throw not.valid; }
		bool IList.IsFixedSize { get { return true; } }

		public String text_rows()
		{
			return arr.Select(x => x.ToTextRow()).StringJoin(Environment.NewLine);
		}

		public String html_rows()
		{
			String s_html = arr.Select(x => x.ToHtmlTableRow()).StringJoin(Environment.NewLine);

			s_html = @"Format:HTML Format
Version:1.0
StartHTML:<<<<<<<1
EndHTML:<<<<<<<2
StartFragment:<<<<<<<3
EndFragment:<<<<<<<4
StartSelection:<<<<<<<3
EndSelection:<<<<<<<3
<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">
<meta http-equiv=""Content-Type"" content=""text/html; charset=UTF-8"" />
<html>
<head><title>foo</title></head>
<body>
<!--StartFragment--><table border=1 style='white-space:nowrap; font-family:consolas;'>
<tr><th colspan=2>index</th><th rowspan=2 width=55><i>m</i><sub>in</sub></th><th rowspan=2>Feature</th><th rowspan=2>Type</th><th rowspan=2 width=55><i>m</i><sub>out</sub></th></tr>
<tr><th>logical</th><th>physical</th></tr>
" + s_html + @"
</table><!--EndFragment-->
</body>
</html>";

			s_html = s_html
					.Replace("<<<<<<<1", s_html.IndexOf("<!DOCTYPE").ToString("00000000"))
					.Replace("<<<<<<<2", s_html.Length.ToString("00000000"))
					.Replace("<<<<<<<3", s_html.IndexOfEnd("<!--StartFragment-->").ToString("00000000"))
					.Replace("<<<<<<<4", s_html.IndexOf("<!--EndFragment-->").ToString("00000000"));

			return s_html;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		IIdentity IIdentity.Trace { get { return tfs; } }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// a reference version of the TfsSlot struct to support derived classes and better navigation performance (compared to 
	/// boxing the struct as an ITfsSlot). This class is marked abstract to enforce the concept that, if your use is not 
	/// important enough to warrant a derived class, then you should probably just use the TfsSlot struct directly.
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//[DebuggerDisplay("{ToString(),nq}")]
	[DebuggerDisplay("{ToStringRight(),nq}", Name = "{ToStringLeft(),nq}")]
	[DebuggerTypeProxy(typeof(SlotRefArray))]
	public unsafe class TfsSlotRef : ITfsSlot, IEquatable<TfsSlotRef>, IEquatable<TfsSlot>, IEquatable<ITfsSlot>,
		ρρType,
		ρρRenderNode
	{
		public TfsSlotRef(Tfs tfs, int ix1)
		{
			this.tfs = tfs;
			this.ix1 = ix1;
		}
		public TfsSlotRef(TfsSlot ts)
			: this(ts.tfs, ts.ix1)
		{
		}
		public TfsSlotRef(ITfsSlot ts)
			: this(ts.Tfs, ts.SlotIndex)
		{
		}
		public TfsSlotRef(Tfs tfs, int i_feat, int mark)
			: this(tfs, tfs.GetEdgeIndex(i_feat, mark))
		{
		}
		public unsafe TfsSlotRef(ConstraintRef cref)
			: this(cref.TfsSlot)
		{
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly Tfs tfs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly int ix1;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int ix0 { [DebuggerStepThrough] get { return ix1 - 1; } }

		///////////////////////////////////////////////////////////////////////
		///
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs Tfs { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough] get { return tfs; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int SlotIndex { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough] get { return ix1; } }
		///
		///////////////////////////////////////////////////////////////////////

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IRenderNode RenderNode
		{
			get { return new RootRenderNode(this); }
			set { throw not.valid; }
		}

		/// <summary>
		/// Converts this reference-type TfsSlotRef into a value-type TfsSlot. Are you sure you mean to do this?
		/// Does your target interface support ITfsSlot? The TfsSlot struct is meant for ephemeral usages during
		/// (and throughout) which the compiler can maintain value-type semantics without boxing.
		/// </summary>
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected TfsSlot TfsSlot { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]  get { return new TfsSlot(tfs, ix1); } }

		/// <summary> to get started along a TfsPath </summary>
		public TfsSlot this[String s_feat] { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough] get { return new TfsSlot(tfs, ix1)[s_feat]; } }
		public TfsSlot this[int i_feat] { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]  get { return new TfsSlot(tfs, ix1)[i_feat]; } }
		public TfsSlot this[FeatureInfo fi] { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]  get { return new TfsSlot(tfs, ix1)[fi.i_feat]; } }
		public TfsSlot this[FsPath fsp] { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]  get { return new TfsSlot(tfs, ix1)[fsp]; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Grammar g { [DebuggerStepThrough]  get { return tfs.Grammar; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public FeatMgr ftm { [DebuggerStepThrough]  get { return tfs.ftm; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Isometrics im { [DebuggerStepThrough]  get { return tfs.im; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TypeUtils tu { [DebuggerStepThrough]  get { return tfs.tu; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int in_feat
		{
			get
			{
				if (tfs == null || ix1 < 0)
					return FeatureInfo.Invalid.i_feat;
				if (ix1 == 0)
					return FeatureInfo.RootNode.i_feat;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.i_feat;
			}
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int i_feat { get { return this.in_feat; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String Feature
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				int i = in_feat;
				if (i < 0 || i == int.MaxValue)
					return "(no feature)";
				return tfs.ftm[i].feature;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String FEATURE
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				int i = in_feat;
				if (i < 0 || i == int.MaxValue)
					return "(no feature)";
				return tfs.ftm[i].FEATURE;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public FeatMark FeatMark
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return FeatMark.Invalid;
				if (ix1 == 0)
					return FeatMark.RootNode;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.FeatMark;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int in_mark
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (tfs == null || ix1 < 0)
					return FeatMark.Invalid.m;
				if (ix1 == 0)
					return FeatMark.RootNode.m;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.mark;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge Edge
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (tfs == null || ix1 < 0)
					return default(Edge);
				if (ix1 == 0)
					return tfs._top_edge;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.e;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge.Flag FlagsId
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (tfs == null || ix1 < 0)
					return 0;
				if (ix1 == 0)
					return tfs._top_edge.FlagsId;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.e_FlagsId;
			}
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int out_mark
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (tfs == null || ix1 < 0)
					return 0;
				if (ix1 == 0)
					return tfs._top_edge.Mark;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.e_Mark;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Type Type
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get { return tfs.tu.GetEdgeType(this.FlagsId); }
			set { throw not.impl; }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String StringValue
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get { return tfs.tu.GetStringValue(this.FlagsId); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String TypeNameOrStringValue
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get { return tfs.tu.TypeNameOrStringValue(this.FlagsId); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String TypeNameOrStringValueDisplay
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get { return tfs.tu.TypeNameOrStringValueDisplay(this.FlagsId); }
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override bool Equals(Object obj)
		{
			ITfsSlot its;
			return (its = obj as ITfsSlot) != null && this.Equals(its);
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool Equals(TfsSlot other)
		{
			return this.tfs == other.tfs && this.ix1 == other.ix1;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool Equals(ITfsSlot other)
		{
			return this.tfs == other.Tfs && this.ix1 == other.SlotIndex;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool Equals(TfsSlotRef other)
		{
			return this.tfs == other.tfs && this.ix1 == other.ix1;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override int GetHashCode()
		{
			return (ix1 << 16) ^ (int)tfs.Id;
		}
		public String ToStringLeft()
		{
			FeatMgr ftm;
			String s = ("[" + ix1.ToString() + "] ").PadLeft(5);

			if (ix1 == 0)
				s += "[TOPMST]";
			else if (ix1 > 0 && tfs != null && (ftm = tfs.ftm) != null)
			{
				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				s += String.Format("{0}/{1}", ate.mark, ftm[ate.i_feat].FEATURE);
			}
			else
				s += "[???]";
			return s;
		}
		public String ToStringRight()
		{
			if (ix1 < 0)
				return "ix1==" + ix1.ToString();

			Edge e = this.Edge;
			//return String.Format("{0,25}  {1}", Edge.TypeInfoFromFlag(ftm, e.FlagsId), Edge.FormatMark(e));
			return String.Format("{0} {1}", Edge.TypeInfoFromFlag(ftm, e.FlagsId), Edge.FormatMark(e));
		}

		public override String ToString()
		{
#if true
			Edge e = this.Edge;
			return ToStringLeft() + " " + Edge.TypeInfoFromFlag(ftm, e.FlagsId) + " " + Edge.FormatMark(e);
#else
			if (tfs == null)
				return "(null tfs)";
			if (ix1 < 0)
				return "(ix1 < 0)";

			arr_tfs_entry ate;
			tfs.GetIndexData(ix1, &ate);
			String s = ate.FeatMark.ToString(tfs.ftm) + " " + ate.e.ToString(ftm, false);
			//s = String.Format("#{0} ", tfs.Id.ToString("X")) + s;
			return s;
#endif
		}

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		TfsSlot[] _BELOW { get { return SlotRefArray.GetConstraints(this); } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		IIdentity IIdentity.Trace { get { return tfs.Trace; } }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public class IdentitySlotRef : TfsSlotRef, IIdentity
	{
		public IdentitySlotRef(IIdentity prv, Tfs tfs, int ix1)
			: base(tfs, ix1)
		{
			this.prv = prv;
		}
		public IdentitySlotRef(IIdentity prv, TfsSlot ts)
			: this(prv, ts.tfs, ts.ix1)
		{
		}
		public IdentitySlotRef(IIdentity prv, ITfsSlot ts)
			: this(prv, ts.Tfs, ts.SlotIndex)
		{
		}
		public IdentitySlotRef(IIdentity prv, Tfs tfs, int i_feat, int mark)
			: this(prv, tfs, tfs.GetEdgeIndex(i_feat, mark))
		{
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		readonly IIdentity prv;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IIdentity Trace { [DebuggerHidden] get { return tfs; } }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}", Name = "{Ix1Display.PadLeft(5),nq}")]
	public unsafe struct TfsSlot :
		ITfsSlot,
		IEquatable<TfsSlot>, IEquatable<ITfsSlot>, IEquatable<TfsSlotRef>, IComparable<TfsSlot>,
		ρρType
	{
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public static readonly IEqualityComparer<TfsSlot> SubstructureComparer;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public static readonly TfsSlot[] None;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public static readonly TfsSlot NotValid;

		static TfsSlot()
		{
			None = Collection<TfsSlot>.None;
			NotValid = new TfsSlot(null, -1);
			SubstructureComparer = new _substructure_comparer();
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public TfsSlot(Tfs tfs, int ix1)
		{
			this.tfs = tfs;
			this.ix1 = ix1;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public TfsSlot(ITfsSlot ts)
		{
			this.tfs = ts.Tfs;
			this.ix1 = ts.SlotIndex;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly Tfs tfs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly int ix1;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public bool IsValid
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return tfs != null && ix1 >= 0; }
		}

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public TfsSlot[] SlotsBelow { get { return SlotRefArray.GetConstraints(tfs, ix1, false); } }


		///////////////////////////////////////////////////////////////////////
		/// 'known' TfsSlots should not be accessed through 'ITfsSlot'
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		Tfs ITfsSlot.Tfs
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return tfs; }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		int ITfsSlot.SlotIndex
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return ix1; }
		}
		///
		///////////////////////////////////////////////////////////////////////



		///////////////////////////////////////////////////////////
		/// navigation
		public TfsSlot this[int i_feat]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0 || i_feat < 0)
					return NotValid;

				int i, m = ix1 == 0 ? tfs._top_edge.Mark : tfs.entries[ix1 - 1].e_Mark;

				return m != 0 && (i = tfs.GetEdgeIndex(i_feat, m)) > 0 ? new TfsSlot(tfs, i) : NotValid;
			}
		}
		public TfsSlot this[FeatureInfo fi]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return this[fi.i_feat]; }
		}
		public TfsSlot this[FsPath fsp]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return fsp[this]; }
		}
		public TfsSlot this[String s_path]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				int dot = s_path.IndexOf('.');
				if (dot != -1)
					return this[s_path.Substring(0, dot)][s_path.Substring(dot + 1)];

				FeatureInfo fi;
				int i, m = this.out_mark;
				return m == 0 || !tfs.ftm.feat_map.TryGetValue(s_path, out fi) || (i = tfs.GetEdgeIndex(fi.i_feat, m)) <= 0 ?
							NotValid :
							new TfsSlot(tfs, i);
			}
		}
		///
		///////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////
		/// list and diff-list
		static IEnumerable<int> GetListIx1s(Tfs tfs, int ix1)
		{
			var im = tfs.im;
			int m, ix1_head;
			do
			{
				m = tfs.GetIx1Mark(ix1);

				if (m == 0 || (ix1_head = tfs.GetEdgeIndex(im.f_ix_list_head, m)) <= 0)
					yield break;

				yield return ix1_head;
			}
			while ((ix1 = tfs.GetEdgeIndex(im.f_ix_list_tail, m)) > 0);
			Debug.Print("TFS list without tail? (1)");
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int ListLength
		{
			get
			{
				if (tfs == null || ix1 < 0)
					return -1;
				int i_walk = ix1;
				int m, c = 0;
				do
				{
					m = tfs.GetIx1Mark(i_walk);

					if (m == 0 || tfs.GetEdgeIndex(im.f_ix_list_head, m) <= 0)
						return c;
					c++;
				}
				while ((i_walk = tfs.GetEdgeIndex(im.f_ix_list_tail, m)) > 0);
				Debug.Print("TFS list without tail? (2)");
				return c;
			}
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TfsSlot[] ListSlots
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return null;
				int m;
				var arr = TfsSlot.None;
				if ((m = tfs.GetIx1Mark(ix1)) != 0)
				{
					var e = GetListIx1s(tfs, ix1).GetEnumerator();
					while (e.MoveNext())
						alib.Array.arr.Append(ref arr, new TfsSlot(tfs, e.Current));
				}
				return arr;
			}
		}
		static IEnumerable<int> GetDiffListListIx1s(Tfs tfs, int ix1)
		{
			if (tfs == null || ix1 < 0)
				yield break;
			int m = tfs.GetIx1Mark(ix1);
			if (m != 0 && (ix1 = tfs.GetEdgeIndex(tfs.im.f_ix_dlist_list, m)) > 0)
				foreach (var i in GetListIx1s(tfs, ix1))
					yield return i;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IEnumerable<TfsSlot> DiffListListSlots
		{
			get
			{
				if (tfs == null || ix1 < 0)
					yield break;
				var e = GetDiffListListIx1s(tfs, ix1).GetEnumerator();
				while (e.MoveNext())
					yield return new TfsSlot(tfs, e.Current);
			}
		}
		///
		///////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////
		/// 
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Grammar g { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough] get { return tfs.Grammar; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public FeatMgr ftm { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough] get { return tfs.ftm; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Isometrics im { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough] get { return tfs.im; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public MrsManager mrsm { [MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough] get { return tfs.mrsm; } }
		///
		///////////////////////////////////////////////////////////


		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge Edge
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return default(Edge);
				if (ix1 == 0)
					return tfs._top_edge;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.e;
			}
		}


		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String FEATURE
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return FeatureInfo.FEATURE; }
		}

		//[DebuggerDisplay("{(\"[\"+ix1.ToString()+\"]\").PadLeft(5),nq} {new FeatMark(i_feat,in_mark).ToString(),nq}", Name = "ix1-Slot / FeatMark")]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public FeatureInfo FeatureInfo
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return FeatureInfo.Invalid;
				if (ix1 == 0)
					return FeatureInfo.RootNode;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);

				int i_feat;
				FeatMgr ftm;

				return (i_feat = ate.i_feat) < 0 || i_feat >= (ftm = tfs.ftm).Count ?
					FeatureInfo.Invalid :
					ftm[i_feat];
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int i_feat
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return FeatureInfo.Invalid.i_feat;
				if (ix1 == 0)
					return FeatureInfo.RootNode.i_feat;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.i_feat;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int in_mark
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return FeatMark.Invalid.m;
				if (ix1 == 0)
					return FeatMark.RootNode.m;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.mark;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int out_mark
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return 0;
				if (ix1 == 0)
					return tfs._top_edge.Mark;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.e_Mark;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge.Flag FlagsId
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return 0;
				if (ix1 == 0)
					return tfs._top_edge.FlagsId;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.e_FlagsId;
			}
		}

		/// <summary> i.e., FlagsId with coreference cleared </summary>
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge.Flag EdgeFlag
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				if (tfs == null || ix1 < 0)
					return agree.Edge.Flag.Bottom;

				if (ix1 == 0)
					return tfs._top_edge.FlagsId & ~Edge.Flag.Coreference;

				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				return ate.e_FlagsId & ~Edge.Flag.Coreference;
			}
		}


		//[DebuggerDisplay("{(tfs==null?\"(null TFS)\":this.Type.ToString()),nq}", Name = "{(tfs==null?\"(null TFS)\":\"“\"+tu.TypeNameOrStringValue(FlagsId)+\"”\"),nq}")]
		//[DebuggerDisplay("{this.Type.Name,nq}")]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Type Type
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return tfs.tu.GetEdgeType(this.FlagsId); }
			set { throw not.impl; }
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String StringValue
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return tfs == null ? "" : tfs.tu.GetStringValue(this.FlagsId); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String TypeNameOrStringValue
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return tfs.tu.TypeNameOrStringValue(this.FlagsId); }
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String TypeNameOrStringValueDisplay
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get { return tfs.tu.TypeNameOrStringValueDisplay(this.FlagsId); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int IntegerValue
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
			get
			{
				var ef = this.FlagsId & ~agree.Edge.Flag.Coreference;
				if (ef != 0)
				{
					int i;
					if (ef.IsIntegerValue())
						return ef.GetIntegerValue();
					var s = tfs.tu.GetStringValue(ef);
					if (s != null && int.TryParse(s, out i))
						return i;
				}
				return 0;
			}
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Double DoubleValue
		{
			get
			{
				var s = tfs.tu.GetStringValue(this.FlagsId);
				Double d;
				return s != null && Double.TryParse(s, out d) ? d : Double.NaN;
			}
		}


		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public int CompareTo(TfsSlot other)
		{
			long d = tfs.Id - other.tfs.Id;
			if (d != 0)
				return (int)d;
			return ix1 - other.ix1;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public override bool Equals(Object obj)
		{
			var other = obj as ITfsSlot;
			return other != null && this.tfs == other.Tfs && this.ix1 == other.SlotIndex;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public bool Equals(ITfsSlot other)
		{
			return other != null && this.tfs == other.Tfs && this.ix1 == other.SlotIndex;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public bool Equals(TfsSlotRef other)
		{
			return other != null && this.tfs == other.Tfs && this.ix1 == other.SlotIndex;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public bool Equals(TfsSlot other)
		{
			return this.tfs == other.tfs && this.ix1 == other.ix1;
		}
		[MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerStepThrough]
		public override int GetHashCode()
		{
			return (ix1 << 16) ^ (int)tfs.Id;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String Ix1Display { get { return "[" + ix1.ToString() + "] "; } }

		public override String ToString()
		{
			if (tfs == null)
				return "(null tfs)";
			if (ix1 < 0)
				return "(ix1 < 0)";
			String s = Ix1Display.PadLeft(5);
			Edge e;
			if (ix1 == 0)
				s += tfs._top_edge.ToString(ftm, true);
			else
			{
				arr_tfs_entry ate;
				tfs.GetIndexData(ix1, &ate);
				s += ate.FeatMark.ShortDisplay(ftm).PadRight(18) + " " + ate.e.ToString(ftm, true);
			}
			return s;
		}


		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		IIdentity IIdentity.Trace { get { return tfs.Trace; } }

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		sealed class _substructure_comparer : IEqualityComparer<TfsSlot>
		{
			public bool Equals(TfsSlot x, TfsSlot y)
			{
				return (x.tfs == y.tfs && x.ix1 == y.ix1) || Subsumption.Check(null, x, y) == Subsumption.Equivalent;
			}
			public int GetHashCode(TfsSlot obj) { return 0; }
		};
	};
}
